using System;
using System.Threading;
using System.Collections.Generic;

using Subsync.CLI;
using Subsync.Core.Sync;

using Gtk;

namespace Subsync.GUI
{
	/// <summary>
	/// Author: Steven Goh Jian Wen with some modifications by Tsz Lai
	/// </summary>
	[System.ComponentModel.ToolboxItem(true)]
	public partial class SimpleFrame : Gtk.Bin
	{
		//Class Variables
		private SyncItem btn1,btn2,btn3; //for sync items
        private Label sync_info; // for sync names		
        private ProgressDialog progress;
		
		//def element values
        private string def_prompt_txt = "Click to Sync";
		
		//logic variables
        private List<Sync> list_of_syncs;
        private int sync_pointer = 0;		
		
		/// <summary>
		/// Constructor
		/// </summary>
		public SimpleFrame ()
		{
			this.Build ();
			
			list_of_syncs = new Config ().GetAllSyncs ();
			
			//init top
			this.PopulateTop ();
			
			//init mid
			this.PopulateSyncItems ();
			
			//init btm
			this.PopulateBtm ();
			
			//startup
			new Thread (delegate() { Views.HandleStartup (); }).Start ();
		}
		
		void PopulateTop ()
		{
			//Initialization
			MinimizeButtonWidget minbtn = new MinimizeButtonWidget();
			this.minimizebuttonalign.Add(minbtn);
			ExpandButtonWidget expbtn = new ExpandButtonWidget ();
			this.expandbuttonalign.Add (expbtn);
			CloseButtonWidget xbtn = new CloseButtonWidget ();
			this.closebuttonalign.Add (xbtn);
			
			//Bind events
			minbtn.Clicked += HandleMinBtnClicked;
			expbtn.Clicked += HandleExpbtnClicked;
			xbtn.Clicked += HandleXbtnClicked;	
		}
		
		/// <summary>
		/// Populate btn1-3
		/// </summary>
		void PopulateSyncItems ()
		{
			if (list_of_syncs.Count >= 1) {
				btn1 = new SyncItem (list_of_syncs[0]);
				jobsframe.Add (btn1);
				btn1.Clicked += HandleBtn1Clicked;
				btn1.Entered += HandleBtn1Entered;
				btn1.Left += HandleBtn1Left;
			}
			if (list_of_syncs.Count >= 2) {
				btn2 = new SyncItem (list_of_syncs[1]);
				jobsframe.Add (btn2);
				btn2.Clicked += HandleBtn2Clicked;
				btn2.Entered += HandleBtn2Entered;
				btn2.Left += HandleBtn2Left;
			}
			if (list_of_syncs.Count >= 3) {
				btn3 = new SyncItem (list_of_syncs[2]);
				jobsframe.Add (btn3);
				btn3.Clicked += HandleBtn3Clicked;
				btn3.Entered += HandleBtn3Entered;
				btn3.Left += HandleBtn3Left;
			}
		}
		
		void PopulateBtm ()
		{
			sync_info = new Label ();
			sync_info.Text = this.def_prompt_txt;
			sync_info.HeightRequest = 26;
			ScrollButtonWidget leftscroll = new ScrollButtonWidget (true);
			ScrollButtonWidget rightscroll = new ScrollButtonWidget (false);
			Alignment alignleftscroll = new Alignment ((float)1.0, (float)0.5, (float)0.2, (float)0.5);
			Alignment alignsyncinfo = new Alignment ((float)0.5, (float)0.5, (float)0.0, (float)0.0);
			Alignment alignrightscroll = new Alignment ((float)0.0, (float)0.5, (float)0.2, (float)0.5);
			alignleftscroll.Add (leftscroll);
			alignsyncinfo.Add (sync_info);
			alignrightscroll.Add (rightscroll);
			alignsyncinfo.WidthRequest = 90;
			
			BottomHbox.Add (alignleftscroll);
			BottomHbox.Add (alignsyncinfo);
			BottomHbox.Add (alignrightscroll);
			
			Pango.FontDescription fontdesc = new Pango.FontDescription ();
			fontdesc.Family = "Arial";
			fontdesc.Size = 10 * (int)Pango.Scale.PangoScale;
			fontdesc.Weight = Pango.Weight.Semibold;
			sync_info.ModifyFont (fontdesc);
			Gdk.Color fontcolor = new Gdk.Color (255, 255, 255);
			sync_info.ModifyFg (StateType.Normal, fontcolor);
			
			//events binding
			leftscroll.Clicked += HandleLeftscrollClicked;
			rightscroll.Clicked += HandleRightscrollClicked;
		}

		//EVENTS
		/// <summary>
		/// Event for when the expansion button is clicked.
		/// It should expand into the expanded view.
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="EventArgs"/>
		/// </param>
		void HandleExpbtnClicked (object sender, EventArgs e)
		{
			this.Toplevel.Destroy ();
			Views.main = null;
			Subsync.CLI.Views.advwin = new AdvanceTop ();
			Subsync.CLI.Views.advwin.Show ();
		}
		
		/// <summary>
		/// Event for handling when the close button is clicked.
		/// It should quit the application.
		/// </summary>
		/// <param name="sender">
		/// A <see cref="System.Object"/>
		/// </param>
		/// <param name="e">
		/// A <see cref="EventArgs"/>
		/// </param>
		void HandleXbtnClicked (object sender, EventArgs e)
		{
			Views.HandleShutdown ();
			Application.Quit ();
		}
		
		void HandleMinBtnClicked (object sender, EventArgs e)
		{
			OperatingSystem os = Environment.OSVersion;
			PlatformID pid = os.Platform;			

			if (Views.tray_minizable){
				if ((pid==PlatformID.Win32NT)||(pid==PlatformID.Win32Windows)){
					Views.main.Hide ();
				}else{
					Views.main.SkipTaskbarHint = true;
					Views.main.Iconify ();
				}			
			}else{
				Views.main.Iconify ();
			}
		}
		
		//SYNCING Events
		void HandleBtn3Clicked (object sender, EventArgs e)
		{
			BeginSync (btn3);
		}

		void HandleBtn2Clicked (object sender, EventArgs e)
		{
			BeginSync (btn2);
		}

		void HandleBtn1Clicked (object sender, EventArgs e)
		{
			BeginSync (btn1);
		}
		
		void HandleBtn3Left (object sender, EventArgs e)
		{
			sync_info.Text = def_prompt_txt;
		}

		void HandleBtn2Left (object sender, EventArgs e)
		{
			sync_info.Text = def_prompt_txt;
		}

		void HandleBtn1Left (object sender, EventArgs e)
		{
			sync_info.Text = def_prompt_txt;
		}

		void HandleBtn3Entered (object sender, EventArgs e)
		{
			sync_info.Text = ((SyncItem)sender).sync_info.name;
		}

		void HandleBtn2Entered (object sender, EventArgs e)
		{
			sync_info.Text = ((SyncItem)sender).sync_info.name;
		}

		void HandleBtn1Entered (object sender, EventArgs e)
		{
			sync_info.Text = ((SyncItem)sender).sync_info.name;
		}
		
		//SCROLLING Events
		void HandleRightscrollClicked (object sender, EventArgs e)
		{
			if (list_of_syncs.Count > 3) {
				
				int btn1_pointer = (this.sync_pointer + 1) % list_of_syncs.Count;
				int btn2_pointer = (this.sync_pointer + 2) % list_of_syncs.Count;
				int btn3_pointer = (this.sync_pointer + 3) % list_of_syncs.Count;
				btn1.sync_info = list_of_syncs[btn1_pointer];
				btn1.Refresh ();
				btn2.sync_info = list_of_syncs[btn2_pointer];
				btn2.Refresh ();
				btn3.sync_info = list_of_syncs[btn3_pointer];
				btn3.Refresh ();
				sync_pointer = btn1_pointer;
			}
		}

		void HandleLeftscrollClicked (object sender, EventArgs e)
		{
			if (list_of_syncs.Count > 3) {
				int btn1_pointer = (this.sync_pointer + list_of_syncs.Count -1) % list_of_syncs.Count;
				int btn2_pointer = (this.sync_pointer + list_of_syncs.Count ) % list_of_syncs.Count;
				int btn3_pointer = (this.sync_pointer + list_of_syncs.Count +1) % list_of_syncs.Count;
				btn1.sync_info = list_of_syncs[btn1_pointer];
				btn1.Refresh ();
				btn2.sync_info = list_of_syncs[btn2_pointer];
				btn2.Refresh ();
				btn3.sync_info = list_of_syncs[btn3_pointer];
				btn3.Refresh ();
				sync_pointer = btn1_pointer;
			}
		}

		//Helpers
		void BeginSync (SyncItem sync_obj)
		{
			progress = new ProgressDialog ("Syncing " + sync_obj.sync_info.name + "...");
			progress.Show ();
			
			new Thread (delegate() {
				bool has_errors = false;
				string error_description = "";
				try {
					sync_obj.sync_info.Execute ();
				}
				catch (SyncNotFound) {
					has_errors = true;
					error_description = "Sync not found.";
				} catch (FolderDoesNotExist) {
					has_errors = true;
					error_description = "Folder does not exist.";
				} catch (RepositoryNotFound) {
					has_errors = true;
					error_description = "Repository cannot be found.";
				} catch (SyncNameConflict) {
					has_errors = true;
					error_description = "Sync name conflicts.";
				} catch (PathAlreadyAWorkingCopy) {
					has_errors = true;
					error_description = "Directory is a SVN working copy, cannot proceed.";
				} catch (DiskSpaceException) {
					has_errors = true;
					error_description = "Disk is full, please clear some space and try again.";
				} catch (Exception) {
					has_errors = true;
					error_description = "An unknown error has occurred.";
				}
				Gtk.Application.Invoke (delegate {
					progress.Destroy ();
					if (has_errors) {
						NotificationDialog error = new NotificationDialog (error_description);
						error.Show ();
					}
				});
			}).Start ();
		}
	}
}
